#include <assert.h>
#include "SypEngine.h"

#ifdef CHECKMEM
#include "mmgr.h"
#endif

namespace Syp
{

InputManager* InputManager::im = 0;

InputManager::InputManager()
{

}

void InputManager::initialise()
{
	if(!im)
	{
		im = new InputManager();
		glfwSetKeyCallback(recieveKey);
		glfwSetMouseButtonCallback(recieveMouseClick);
		glfwEnable(GLFW_KEY_REPEAT);
		im->numOfBufferedKeys = 0;
		im->keyEvent.resize(10);
	}
}

InputManager& InputManager::getInputManager()
{
		assert(im && "InputManager cannot be returned until it has been initialised!");
		return (*im);
};

void InputManager::subscribeToMouseUpdates(const MouseUpdateReciever::slot_type& gb)
{
	mouseUpdate.connect(gb);
}

void InputManager::release()
{
	if(im)
	{
		delete im;
		im = 0;
	}
}

void InputManager::recieveKey(int key, int state)
{
	KeyEvent e;
	e.key = key;
	e.state = state;
	if(im->numOfBufferedKeys >= im->keyEvent.size())
	{
		//im->keyEvent.clear();
		im->numOfBufferedKeys = 0;
	}
	*(im->keyEvent.begin() + im->numOfBufferedKeys) = e;
	++im->numOfBufferedKeys;
	assert(im->numOfBufferedKeys<=im->keyEvent.size() && "Input Buffer exceeded");

}

const MouseState& InputManager::getMouseStateRef()
{
	return ms;
}

void InputManager::getInput()
{
	ms.lastMouseX = ms.mouseX;
	ms.lastMouseY = ms.mouseY;
	glfwGetMousePos(&ms.mouseX ,&ms.mouseY);
	ms.mouseY = Renderer::getRenderer().getHeight() - ms.mouseY;

	//Same time we will signal subscribers on updates
	mouseUpdate(ms, MOUSEMOVE);
}

void InputManager::recieveMouseClick(int key, int state)
{
	MouseEvent me = MOUSEUNDEFINED;
	if(key == SYP_MOUSE_BUTTON_LEFT)
	{
		if(state)
		{
			im->ms.mouseLeft = true;
			me = MOUSELEFTDOWN;
		}
		else
		{
            im->ms.mouseLeft = false;
			me = MOUSELEFTUP;
		}
	}
	else if(key == SYP_MOUSE_BUTTON_RIGHT)
	{
		if(state)
		{
			im->ms.mouseRight = true;
			me = MOUSERIGHTDOWN;
		}
		else
		{
            im->ms.mouseRight = false;
			me = MOUSERIGHTUP;
		}
	}
	else if(key == SYP_MOUSE_BUTTON_MIDDLE)
	{
		if(state)
		{
			im->ms.mouseMiddle = true;
			me = MOUSEMIDDLEDOWN;
		}
		else
		{
            im->ms.mouseMiddle = false;
			me = MOUSEMIDDLEUP;
		}
	}
	//Same time we will signal subscribers on updates
	im->mouseUpdate(im->ms,me);
}

KeyEvent InputManager::getKey()
{

	KeyEvent e;
	if(numOfBufferedKeys>0)
	{
	e = *keyEvent.begin();
	--numOfBufferedKeys;
	return e;
	}
	e.key = SYP_KEY_UNKNOWN;
	return e;

}
}
